package com.xyht.medicine_management_system.modules.payment.alipay.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xyht.medicine_management_system.common.commonReturn.CommonCodeEnum;
import com.xyht.medicine_management_system.common.commonReturn.CommonResult;
import com.xyht.medicine_management_system.common.commonReturn.ExceptionCast;
import com.xyht.medicine_management_system.common.util.TimeUtil;
import com.xyht.medicine_management_system.modules.consumptionPoint.constant.ConsumptionPointRecordConstant;
import com.xyht.medicine_management_system.modules.consumptionPoint.constant.PointRuleStatusConstant;
import com.xyht.medicine_management_system.modules.consumptionPoint.entity.MmsConsumptionPointRecord;
import com.xyht.medicine_management_system.modules.consumptionPoint.entity.MmsConsumptionPointRule;
import com.xyht.medicine_management_system.modules.consumptionPoint.entity.MmsUserConsumptionPoint;
import com.xyht.medicine_management_system.modules.consumptionPoint.mapper.MmsConsumptionPointRecordMapper;
import com.xyht.medicine_management_system.modules.consumptionPoint.mapper.MmsConsumptionPointRuleMapper;
import com.xyht.medicine_management_system.modules.consumptionPoint.mapper.MmsUserConsumptionPointMapper;
import com.xyht.medicine_management_system.modules.coupon.constant.UserCouponRelationConstant;
import com.xyht.medicine_management_system.modules.coupon.entity.MmsUserCouponRelation;
import com.xyht.medicine_management_system.modules.coupon.entity.resp.MmsUserCouponRelationResp;
import com.xyht.medicine_management_system.modules.coupon.service.MmsUserCouponRelationService;
import com.xyht.medicine_management_system.modules.order.constant.*;
import com.xyht.medicine_management_system.modules.order.entity.MmsOrder;
import com.xyht.medicine_management_system.modules.order.entity.MmsOrderMedicineInfo;
import com.xyht.medicine_management_system.modules.order.entity.MmsOrderRefund;
import com.xyht.medicine_management_system.modules.order.entity.MmsOrderSchedule;
import com.xyht.medicine_management_system.modules.order.entity.resp.OrderMedicineInfoResp;
import com.xyht.medicine_management_system.modules.order.mapper.MmsOrderMapper;
import com.xyht.medicine_management_system.modules.order.mapper.MmsOrderMedicineInfoMapper;
import com.xyht.medicine_management_system.modules.order.mapper.MmsOrderRefundMapper;
import com.xyht.medicine_management_system.modules.order.mapper.MmsOrderScheduleMapper;
import com.xyht.medicine_management_system.modules.order.util.OrderScheduleUtil;
import com.xyht.medicine_management_system.modules.order.util.OrderUtil;
import com.xyht.medicine_management_system.modules.payment.alipay.req.BizContentReq;
import com.xyht.medicine_management_system.modules.payment.alipay.req.RoyaltyDetail;
import com.xyht.medicine_management_system.modules.payment.alipay.service.AliService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.RoundingMode;
import java.util.HashMap;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.xyht.medicine_management_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.medicine_management_system.modules.payment.constant.CommonConstant.ALIPAY_PUBLIC_KEY;

@Service
@Log4j2
public class AliServiceImpl implements AliService {
    @Resource
    private PlatformTransactionManager transactionManager; // 事务
    @Resource
    private MmsOrderMapper mmsOrderMapper;
    @Resource
    private MmsOrderScheduleMapper mmsOrderScheduleMapper;
    @Resource
    private OrderUtil orderUtil;
    @Resource
    private OrderScheduleUtil orderScheduleUtil;
    @Resource
    private MmsOrderMedicineInfoMapper mmsOrderMedicineInfoMapper;
    @Resource
    private MmsConsumptionPointRuleMapper mmsConsumptionPointRuleMapper;
    @Resource
    private MmsConsumptionPointRecordMapper mmsConsumptionPointRecordMapper;
    @Resource
    private MmsUserConsumptionPointMapper mmsUserConsumptionPointMapper;
    @Resource
    private MmsOrderRefundMapper mmsOrderRefundMapper;
    @Resource
    private MmsUserCouponRelationService mmsUserCouponRelationService;

    @Override
    public String aliPayCallback(HttpServletRequest request, HttpServletResponse response) {
        log.info("开始+++++++");
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            // 乱码解决，这段代码在出现乱码时使用。
            // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }

        String charset = params.get("charset");
        boolean checkResult;
        try {
            log.info("开始验签+++++++");
            checkResult = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, charset, "RSA2");
        } catch (AlipayApiException e) {
            log.error("异常，验签失败+++++++++++++");
            e.printStackTrace();
            return "fail";
        }
        if (!checkResult) {
            log.info("验签失败+++++++");
        }
        log.info("++++++++++params" + JSONObject.toJSONString(params));
        String biz_content = params.get("biz_content");
        log.info("++++++++++" + biz_content);


        // 开启事务
        DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
        // 嵌套事务 PROPAGATION_REQUIRES_NEW 每次开启一个新的事务
        dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        // 设置嵌套事务
        TransactionStatus status = transactionManager.getTransaction(dt);
        try {
            // 支付回调
            if (params.get("notify_type").equals("trade_status_sync") && params.get("trade_status").equals("TRADE_SUCCESS")) {
                // 查询订单是否存在
                MmsOrder order = mmsOrderMapper.selectById(params.get("out_trade_no"));
                // 订单不存在
                if (order == null) {
                    return "success";
                }
                // 订单已支付
                if (orderUtil.isPaid(order.getId())) {
                    return "success";
                }

                // 关闭定时任务
                List<MmsOrderSchedule> paymentScheduleList = mmsOrderScheduleMapper.selectList(new LambdaQueryWrapper<MmsOrderSchedule>()
                        .eq(MmsOrderSchedule::getOrderId, order.getId())
                        .eq(MmsOrderSchedule::getIsClose, false) // 状态未结束
                        .eq(MmsOrderSchedule::getType, OrderScheduleConstant.ORDER_SCHEDULE_TYPE_PAYMENT)); // 支付进度
                if (!paymentScheduleList.isEmpty()) {
                    // 关闭支付定时任务
                    for (MmsOrderSchedule paymentSchedule : paymentScheduleList) {
                        paymentSchedule.setIsClose(true); // 定时任务结束
                        paymentSchedule.setEndTime(new Date()); // 结束时间
                        paymentSchedule.setUpdateUserId(ProcessApproverConstant.PROCESS_APPROVER_SYSTEM); // 修改人
                        int updNum = mmsOrderScheduleMapper.updateById(paymentSchedule);
                        if (updNum != 1) { // 修改失败
                            rollback(status); // 手动回滚事务
                            return "fail";
                        }
                    }
                }

                // 记录订单包含药品信息
                List<OrderMedicineInfoResp> medicineInfoRespList = JSON.parseArray(order.getMedicineInfo(), OrderMedicineInfoResp.class);
                for (OrderMedicineInfoResp medicineInfoResp : medicineInfoRespList) {
                    MmsOrderMedicineInfo orderMedicineInfo = new MmsOrderMedicineInfo();
                    orderMedicineInfo.setOrderId(order.getId());
                    orderMedicineInfo.setType(OrderMedicineInfoConstant.ORDER_MEDICINE_INFO_ORDER);
                    orderMedicineInfo.setMedicineInfo(JSON.toJSONString(medicineInfoResp.getMedicine()));
                    orderMedicineInfo.setMedicineCode(medicineInfoResp.getMedicine().getMedicineCode());
                    orderMedicineInfo.setNum(medicineInfoResp.getMedicineNum());
                    int medicineInfoInsertNum = mmsOrderMedicineInfoMapper.insert(orderMedicineInfo);
                    if (medicineInfoInsertNum != 1) {
                        ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.FAIL));
                    }
                }

                // 修改订单状态等信息
                order.setPaymentTransactionId(params.get("trade_no")); // 支付订单号
                BigDecimal totalAmount = new BigDecimal(params.get("total_amount"));
                order.setPaymentAmount(totalAmount); // 支付金额
                order.setPaymentMethod(OrderConstant.ORDER_PAYMENT_METHOD_ALIPAY); // 订单支付方式: 支付宝支付
                order.setPaymentTime(TimeUtil.StringtoDate(params.get("gmt_payment"))); // 支付时间
                order.setOrderStatus(OrderConstant.ORDER_STATUS_TO_BE_DELIVERED); // 待发货
                int orderUpdNum = mmsOrderMapper.updateById(order);
                if (orderUpdNum != 1) {
                    rollback(status); // 手动回滚事务
                    return "fail";
                }

                // 创建订单定时任务(发货进度)
                MmsOrderSchedule deliverySchedule = orderScheduleUtil.generateOrderScheduleByType(
                        order.getId(),
                        OrderScheduleConstant.ORDER_SCHEDULE_TYPE_DELIVERY,
                        OrderScheduleConstant.ORDER_SCHEDULE_CREATOR_SYSTEM);
                if (deliverySchedule == null) {
                    rollback(status); // 手动回滚事务
                    return "fail";
                }
                // 创建订单定时任务(订单结束进度)
                MmsOrderSchedule orderEndSchedule = orderScheduleUtil.generateOrderScheduleByType(
                        order.getId(),
                        OrderScheduleConstant.ORDER_SCHEDULE_TYPE_ORDER_END,
                        OrderScheduleConstant.ORDER_SCHEDULE_CREATOR_SYSTEM);
                if (orderEndSchedule == null) {
                    rollback(status); // 手动回滚事务
                    return "fail";
                }

                // 消费成功按规则转化积分
                Date nowDate = new Date();
                List<MmsConsumptionPointRule> pointRuleList = mmsConsumptionPointRuleMapper.selectList(new LambdaQueryWrapper<MmsConsumptionPointRule>()
                        .eq(MmsConsumptionPointRule::getStatus, PointRuleStatusConstant.POINT_RULE_STATUS_ENABLE)
                        .le(MmsConsumptionPointRule::getStartDate, nowDate)
                        .ge(MmsConsumptionPointRule::getEndDate, nowDate));
                if (!pointRuleList.isEmpty()) {
                    MmsConsumptionPointRule pointRule = pointRuleList.get(0);
                    // 所获积分 = 总金额 * 积分转化率 (小数点后四舍五入)
                    int points = order.getTotalAmount().multiply(BigDecimal.valueOf(pointRule.getPointsRate())).setScale(0, RoundingMode.HALF_UP).intValue();

                    MmsConsumptionPointRecord pointRecord = new MmsConsumptionPointRecord();
                    pointRecord.setUserId(order.getUserId());
                    pointRecord.setOrderId(order.getId());
                    pointRecord.setAmount(order.getTotalAmount());
                    pointRecord.setPoints(points);
                    pointRecord.setStatus(ConsumptionPointRecordConstant.POINT_RECORD_STATUS_INCREASE);
                    pointRecord.setType(ConsumptionPointRecordConstant.POINT_RECORD_TYPE_PURCHASE);
                    pointRecord.setMedicineInfo(order.getMedicineInfo());
                    pointRecord.setPaymentMethod(order.getPaymentMethod());

                    List<MmsUserConsumptionPoint> userPointList = mmsUserConsumptionPointMapper.selectList(new LambdaQueryWrapper<MmsUserConsumptionPoint>()
                            .eq(MmsUserConsumptionPoint::getUserId, order.getUserId()));
                    // 计算用户当前总积分
                    int totalPoints = 0;
                    if (userPointList.isEmpty()) {
                        totalPoints = points;

                        // 创建积分账户
                        MmsUserConsumptionPoint userPoint = new MmsUserConsumptionPoint();
                        userPoint.setUserId(order.getUserId());
                        userPoint.setPoints(totalPoints);
                        mmsUserConsumptionPointMapper.insert(userPoint);
                    } else {
                        MmsUserConsumptionPoint userPoint = userPointList.get(0);
                        totalPoints = points + userPoint.getPoints();

                        // 修改积分余额
                        userPoint.setPoints(totalPoints);
                        mmsUserConsumptionPointMapper.updateById(userPoint);
                    }
                    pointRecord.setTotalPoints(totalPoints);

                    mmsConsumptionPointRecordMapper.insert(pointRecord);
                }
                return "success";
            } else if (params.get("notify_type").equals("trade_status_sync") && params.get("trade_status").equals("TRADE_CLOSED")) { // 退款
                // 查询退款记录是否存在
                MmsOrderRefund orderRefund = mmsOrderRefundMapper.selectById(params.get("out_biz_no"));
                if (orderRefund == null) {
                    return "fail";
                }
                // 已退款
                if (orderRefund.getRefundAmount() != null && orderRefund.getRefundAmount().compareTo(BigDecimal.valueOf(0)) > 0) {
                    return "success";
                }
                // 查询订单是否存在
                MmsOrder refundOrder = mmsOrderMapper.selectById(params.get("out_trade_no"));
                // 订单不存在
                if (refundOrder == null) {
                    return "fail";
                }

                // 退还优惠券
                if (!isNullOrEmpty(refundOrder.getCouponInfo())) { // 存在优惠券信息
                    MmsUserCouponRelationResp couponInfo = JSONObject.parseObject(refundOrder.getCouponInfo(), MmsUserCouponRelationResp.class);
                    if (couponInfo != null) {
                        MmsUserCouponRelation userCoupon = mmsUserCouponRelationService.getById(couponInfo.getId());
                        if (userCoupon != null) {
                            // 优惠券状态修改为未使用
                            userCoupon.setIsUse(UserCouponRelationConstant.USER_COUPON_RELATION_NOT_USE);
                            boolean couponUpdSuccess = mmsUserCouponRelationService.updateById(userCoupon);
                            if (!couponUpdSuccess) { // 修改失败
                                rollback(status); // 手动回滚事务
                                return "fail";
                            }
                        }
                    }
                }

                // 退还积分
                if (refundOrder.getIsUsePoint() != null && refundOrder.getIsUsePoint()) {
                    MmsConsumptionPointRecord pointRecord = mmsConsumptionPointRecordMapper.selectById(refundOrder.getPointRecordId());

                    // 添加退还记录
                    MmsConsumptionPointRecord backPointRecord = new MmsConsumptionPointRecord();
                    BeanUtils.copyProperties(pointRecord, backPointRecord, "id");
                    backPointRecord.setStatus(ConsumptionPointRecordConstant.POINT_RECORD_STATUS_INCREASE);
                    mmsConsumptionPointRecordMapper.insert(backPointRecord);

                    // 退还积分
                    List<MmsUserConsumptionPoint> userPointList = mmsUserConsumptionPointMapper.selectList(new LambdaQueryWrapper<MmsUserConsumptionPoint>()
                            .eq(MmsUserConsumptionPoint::getUserId, refundOrder.getUserId()));
                    MmsUserConsumptionPoint userPoint = userPointList.get(0);
                    // 当前积分 = 原积分 + 退还积分
                    userPoint.setPoints(userPoint.getPoints() + pointRecord.getPoints());
                    mmsUserConsumptionPointMapper.updateById(userPoint);
                }

                // 修改退款记录
                orderRefund.setRefundId(params.get("out_biz_no")); // 微信退款id
                orderRefund.setRefundAmount(BigDecimal.valueOf(Double.parseDouble(params.get("refund_fee")))); // 退款金额
                orderRefund.setRefundTime(TimeUtil.StringtoDate(params.get("gmt_refund"))); // 退款时间
                orderRefund.setStatus(OrderRefundConstant.ORDER_REFUND_STATUS_REFUNDED); // 退货状态: 已退款
                int refundUpdNum = mmsOrderRefundMapper.updateById(orderRefund);
                if (refundUpdNum != 1) {
                    rollback(status); // 手动回滚事务
                    return "fail";
                }

                // 修改订单包含药品信息
                MmsOrderMedicineInfo orderMedicineInfo = new MmsOrderMedicineInfo();
                orderMedicineInfo.setRefundId(orderRefund.getId());
                orderMedicineInfo.setType(OrderMedicineInfoConstant.ORDER_MEDICINE_INFO_REFUND);
                int orderMedicineInfoUpdNum = mmsOrderMedicineInfoMapper.update(orderMedicineInfo, new LambdaQueryWrapper<MmsOrderMedicineInfo>()
                        .eq(MmsOrderMedicineInfo::getOrderId, refundOrder.getId()));
                if (orderMedicineInfoUpdNum < 1) {
                    ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.FAIL));
                }

                // 修改订单状态
                Date nowDate = new Date(); // 当前时间
                refundOrder.setIsClose(OrderConstant.ORDER_IS_CLOSE_YES); // 订单结束
                refundOrder.setEndTime(nowDate); // 订单结束时间
                int refundOrderUpdNum = mmsOrderMapper.updateById(refundOrder);
                if (refundOrderUpdNum != 1) { // 修改失败
                    rollback(status); // 手动回滚事务
                    return "fail";
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            // 手动回滚事务
            transactionManager.rollback(status);
        } finally {
            if (status.isNewTransaction() && !status.isCompleted()) {
                transactionManager.commit(status);
            }
        }

        return "success";
    }

    @Override
    public String aliPayProfitSharingCallback(HttpServletRequest request, HttpServletResponse response) {
        log.info("开始+++++++");
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            // 乱码解决，这段代码在出现乱码时使用。
            // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }

        String charset = params.get("charset");
        boolean checkResult;
        try {
            log.info("开始验签+++++++");
            checkResult = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, charset, "RSA2");
        } catch (AlipayApiException e) {
            log.error("异常，验签失败+++++++++++++");
            e.printStackTrace();
            return "fail";
        }
        if (!checkResult) {
            log.info("验签失败+++++++");
        }
        log.info("++++++++++params" + JSONObject.toJSONString(params));
        String biz_content = params.get("biz_content");
        log.info("++++++++++" + biz_content);

        // 开启事务
        DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
        // 嵌套事务 PROPAGATION_REQUIRES_NEW 每次开启一个新的事务
        dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        // 设置嵌套事务
        TransactionStatus status = transactionManager.getTransaction(dt);
        try {
            if (params.get("notify_type").equals("trade_status_sync") && params.get("trade_status").equals("TRADE_SUCCESS")) { // 分账通知
                // 查询订单
                MmsOrder profitOrder = mmsOrderMapper.selectById(params.get("out_trade_no"));
                if (profitOrder == null) {
                    rollback(status); // 手动回滚事务
                    return "fail";
                }

                // 已分账
                if (!isNullOrEmpty(profitOrder.getProfitSharingTime())) {
                    rollback(status); // 手动回滚事务
                    return "fail";
                }

                profitOrder.setProfitSharingTime(TimeUtil.StringtoDate(params.get("notify_time")));
                int profitOrderUpdNum = mmsOrderMapper.updateById(profitOrder);
                if (profitOrderUpdNum != 1) {
                    rollback(status); // 手动回滚事务
                    return "fail";
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            // 手动回滚事务
            transactionManager.rollback(status);
        } finally {
            if (status.isNewTransaction() && !status.isCompleted()) {
                transactionManager.commit(status);
            }
        }
        return "success";
    }

    /**
     * 手动回滚事务
     *
     * @param status 嵌套事务
     */
    private void rollback(TransactionStatus status) {
        // 手动回滚事务
        transactionManager.rollback(status);
        if (status.isNewTransaction() && !status.isCompleted()) {
            transactionManager.commit(status);
        }
    }

}
